Function.prototype.myCall = function (context) {
    if (typeof this !== 'function') {
        throw TypeError(`caller must be a function`)
    }
    context = context || window
    context.fn = this
    let res = context.fn([...arguments].slice(1))
    delete context.fn
    return res
}

Function.prototype.myApply = function (context) {
    if (typeof this !== 'function') {
        throw TypeError(`caller must be a function`)
    }
    context = context || window
    const fnsymbol = Symbol()
    context[fnsymbol] = this
    let res = null
    if (arguments[1]) {
        res = context[fnsymbol](...arguments[1])
    } else {
        res = context[fnsymbol]()
    }
    delete context[fnsymbol]
    return res
}

Function.prototype.myBind = function (context) {
    if (typeof this !== 'function') {
        throw TypeError(`caller must be a function`)
    }
    context = context || window
    const fn = this
    const args = [...arguments].slice(1)
    return function Fn () {
        fn.apply(
            this instanceof Fn ? Fn : context,
            [...args].concat(...arguments)
        )
    }
}